<?php

namespace App\Library\ETH;

use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Web3;
use Web3\Formatters\TransactionFormatter;

/**
 * 以太坊RPC连接接口
 * 测试环境需要node的testrpc，正式环境需要以太坊的geth客户端
 */
class EthereumFunction
{
    protected $web3;

    public function __construct()
    {
        //连接以太坊
        $web3 = new Web3(new HttpProvider(new HttpRequestManager('http://127.0.0.1:8545', 0.1)));

        $this->web3 = $web3;
    }

    /**
     * 创建一个以太坊新账号
     * @return array [type] [description]
     */
    public function createWalletAddress()
    {
        $personal   = $this->web3->personal;
        $newAccount = '';
        $password = getCode(3, 9);
        //注册新账号
        $personal->newAccount('123456', function ($err, $account) use (&$newAccount) {
            if ($err !== null) {
                //echo 'Error: ' . $err->getMessage();
                return false;
            }
            $newAccount = $account;
        });

        return ['account' => $newAccount, 'password' => $password];
    }

    /**
     * 根据地址获取余额
     * @param  [type] $account [description]
     * @return [type]          [description]
     */
    public function getBalanceByAddress($account)
    {
        $eth = $this->web3->eth;
        $newBalance = '';

        $eth->getBalance($account, function ($err, $balance) use (&$newBalance) {
            if ($err !== null) {
                //echo 'Error: ' . $err->getMessage();
                return false;
            }
            //$newBalance = $balance;
            $newBalance = $this->fromWei($balance->toString());
        });
        //单位转换
        //$bal = $newBalance->toString();
        //$wei = $this->fromWei($bal);

        return $newBalance;
    }

    /**
     * 获取所有以太坊账号(下标0为默认账号)
     * @return string [type] [description]
     */
    public function getAllAccount()
    {
        $eth = $this->web3->eth;
        $arr = '';
        $eth->accounts(function ($err, $accounts) use (&$arr) {
            if ($err !== null) {
                echo 'Error: ' . $err->getMessage();
                return false;
            }
            $arr = $accounts;
        });

        return $arr;
    }

    public function formatterData($from, $to, $gas, $value, $data)
    {
        $formatter = new TransactionFormatter;
        $transaction = $formatter->format([
            'from' => $from,
            'to' => $to,
            'gas' => $gas,
            'gasPrice' => $gas,
            'value' => $value,
            'data' => $this->toHex($data),
            'nonce' => '0x1'
        ]);

        return $transaction;
    }

    /**
     * 发起交易
     * @param $fromAccount
     * @param $toAccount
     * @param $value
     * @internal param $ [type] $fromAccount [打款账号]
     * @internal param $ [type] $toAccount   [收款账号]
     * @internal param $ [type] $value       [金额]
     */
    public function makeTransaction($fromAccount, $toAccount, $value)
    {
        $eth = $this->web3->eth;

        $eth->sendTransaction([
            'from' => $fromAccount,
            'to' => $toAccount,
            'value' => $value
        ], function ($err, $transaction) use ($eth, $fromAccount, $toAccount) {
            if ($err !== null) {
                //echo 'Error: ' . $err->getMessage();
                return ['status' => 0, 'msg' => $err->getMessage()];
                //return false;
            }

            return $transaction;
        });
    }

    public function unlockAccount($account)
    {
        $this->web3->personal->unlockAccount($account, '123456', function ($err, $unlocked) {
            if ($err !== null) {
                //echo 'Error: ' . $err->getMessage();
                return ['status' => 0, 'msg' => $err->getMessage()];
            }
            if ($unlocked) {
                //echo 'New account is unlocked!' . PHP_EOL;
                return true;
            } else {
                //echo 'New account isn\'t unlocked' . PHP_EOL;
                return ['status' => 0, 'msg' => '解锁失败'];
            }
        });
    }

    /**
     * 转16进制
     * @param  [type] $value [description]
     * @return [type]        [description]
     */
    public function toHex($value)
    {
        return $this->web3->Utils::toHex($value, true);
    }

    /**
     * 转为wei单位
     * @param  [type] $value [description]
     * @return [type]        [description]
     */
    public function toWei($value)
    {
        $wei = $this->web3->Utils::toWei($value, 'ether');

        return $wei->toString();
    }

    /**
     * 以太币转换单位
     * @param  [type] $value [description]
     * @return [type]        [description]
     */
    public function fromWei($value)
    {
        list($bnq, $bnr) = $this->web3->Utils::fromWei($value, 'ether');

        return $bnq->toString();
    }

    /**
     * 验证地址是否合法
     * @param  [type] $value [description]
     * @return bool [type]        [description]
     */
    public function addressValidator($value)
    {
        if (!is_string($value)) {
            return false;
        }

        return (preg_match('/^0x[a-fA-F0-9]{40}$/', $value) >= 1);
    }
}
